package futbol.tacticas.concursantes.The1A;


import futbol.tacticas.*;
import futbol.tacticas.concursantes.Tactica;
import java.awt.*;
import java.util.*;


public class Tactica1A implements Tactica {
    
	public final int nbBP = 3;
	private FutureSimulator fs;
	
	public Tactica1A(){
		color = false;
		bh = new BallBehaviour();
		fs = new FutureSimulator(bh,playersSpeed);
		for (int i = 0; i < playersSpeed.length; ++i)
			everybodySpeed[i] = playersSpeed[i];
	}
	
    Random rand=new Random();
    
    /**Team Name*/
    public String getNombre() {
        return "1A";
    }    

    private boolean color;
    /**Up Color*/
    public Color getColor1() {
        return Color.LIGHT_GRAY;
    }
    /**Down Color*/
    public Color getColor2() {
        return Color.BLUE;
    }
    
    /**Number Color*/
    public Color getColorNumero() {
    	if (color)
    		return Color.WHITE;
    	return Color.BLACK;
    }

    /**Return the n player's strength*/
    public int getFuerza(int n) {
    	return 10 - playersSpeed[n];
    }
    
    private Point[] players;
    public int spositions[][]=new int[][]
    {{-150,0}, {-100,40}, {-100,-40}, {-40,0}, {-40,100},{-40,-100}, {10,50},{10,-50}, {50,0},{100,-30},{100,30}};                                        
    //{{-150,0}, {-100,80}, {-100,-80}, {-40,0}, {-40,100},{-40,-100}, {30,100},{30,-100}, {60,80},{60,-80},{80,0}};                                              
    
    public final int[] playersSpeed = new int[] {3,3,3,6,6,6,6,6,6,3,3};      
        
    private Point[] enemies;
    public int[] enemiesSpeed = new int[] {3,3, 4,4, 4,4, 3,3 ,3,3,3};   
    
    private Point[] everybody = new Point[22];
    public int[] everybodySpeed = new int[] {4,4,4,4,4,4,4,4,4,4,4, 3,3, 4,4, 4,4, 3,3 ,3,3,3};   
        
    
    
    public int getXInicial(int n) {
        return spositions[n][0];
    }
    

    public int getYInicial(int n) {
    	return spositions[n][1];
    }
    
    int nearest = 0;
    Point b;

    BallBehaviour bh;
    static final int numAngles = 10;
    
    public Point angstrToPos(Point player, Point ball, double ang, int str, int maxStr){
    	double dist1 = -1d;
    	double dist2 = -1d;
    	//double dist = Math.ceil(50d / (double)maxStr) * str;
    	

    	
    	for (double dist = 0; dist < 60; dist++) {
	    	double x = ball.getX() + Math.cos(ang)*dist; 
	    	double y = ball.getY() + Math.sin(ang)*dist;    		
	    	Point res = new Point();
	    	res.setLocation(x,y);
	    	int nGrado=100;
	        double nDis=Utils.Distance(player, res);
	        if (nDis<50) nGrado=(int)(nDis*2);
	        double fuerza = maxStr;       
	            
	        if (((int)(fuerza*nGrado/100)) == str)
	        {
	        	dist2 = dist;
	        	if (dist1 < 0)
	        		dist1 = dist;	        	
	        }else if (((int)(fuerza*nGrado/100)) > str){
	        	break;
	        }
	        dist++;
    	}
    	double dist;
    	if (str == maxStr)
    		dist = 60;
    	else
    		dist = (dist1 + dist2) / 2;
    	double x = ball.getX() + Math.cos(ang)*dist; 
    	double y = ball.getY() + Math.sin(ang)*dist;     	
    	Point res = new Point();
    	res.setLocation(x,y);
    	return res;
    }
    
    public void whatToDo(int n, Vector<Comando> actions){   	
    	
    	int strength = getFuerza(n);    	
       	Point goal = new Point (160,0);
 
    	FutureSimulator fsEverybody = new FutureSimulator(everybodySpeed);
    	fsEverybody.setPlayersPosition(everybody);
    	BallBehaviour bh = new BallBehaviour();
    	int j = 0;
    	
    	FutureNearest[] nearestPlayers = new FutureNearest[strength*20*numAngles];
    	Point[] shootPoints = new Point[strength*20*numAngles];
    	int[] strs = new int[strength*20*numAngles];
    	double[] angles = new double[strength*20*numAngles];    	
    	
    	double angleStep = 1.005*Math.PI/10/numAngles;
    	DoubleFor : for (int str = 1; str <= strength; str++){
    		for (double angle = 0; angle < 2*Math.PI; angle+=angleStep){ //20*numAngles angles
    			Point shootPoint = angstrToPos(players[n], b, angle, str, strength);    			
    			Point[] futureBall = bh.getShootPredictions(players[n], b, shootPoint, strength);
    			nearestPlayers[j] = fsEverybody.getFutureNearestPlayer(futureBall, bh.getCatchable());
    			shootPoints[j] = shootPoint;
    			strs[j] = str;
    			angles[j] = angle;
    			if (++j >= shootPoints.length)
    				break DoubleFor;    			
    		}
    	}
    	
    	int[] goodPass = new int[strength*20*numAngles];
    	for (int i = 0; i < goodPass.length; ++i){
    		if (nearestPlayers[i].getPlayer() < 11)
    			goodPass[i] = 1;
    		               
    	}    	
    	
    	int[] probaGoodPass = new int[strength*20*numAngles];
    	for (int i = 0; i < probaGoodPass.length; ++i){
    		probaGoodPass[i] = sumAround(goodPass, i, numAngles);
    	}
    	
    	double distMin = 1000;
    	int probaMax = 0;
    	int res = -1;
    	
    	for (int i = 0; i < probaGoodPass.length; ++i){
    		int proba = probaGoodPass[i];
    		if (proba > probaMax){
    			probaMax = proba;
    			distMin = 1000; 
    		}

    		if (proba >= probaMax){
    			double dist = Utils.Distance(nearestPlayers[i].getPoint(), goal);
    			if (nearestPlayers[i].getPlayer() < 0){
    				proba += 8;
    				dist = -100 - strs[i];
    			}
    			else if (nearestPlayers[i].getPlayer() > 30)
    				continue;
    			else if (n < 9 && nearestPlayers[i].getPlayer() == 10 && players[10].x > 0){
    				proba += 4;
    				dist = -1;   
    			}
    			else if (n < 9 && nearestPlayers[i].getPlayer() == 9 && players[9].x > 0){
    				proba += 4;
    				dist = -1;     			
    			}
    			
        		if (proba > probaMax){
        			probaMax = proba;
        			distMin = 1000; 
        		}    			
    			if (dist < distMin){
    				distMin = dist;
    				res = i;
    			}    				
    		}    		                          
    	}
    	
    	if (res >= 0){
    		Point destination = nearestPlayers[res].getPoint();
    		Point shootPoint = shootPoints[res];
    		actions.add(new ComandoGolpearBola(n, shootPoint.getX(), shootPoint.getY()));
    		actions.add(new ComandoIrA(nearestPlayers[res].getPlayer(), destination.getX(), destination.getY()));
    		Utils.strenght = strs[res];
    		/*if (probaMax < 2*numAngles + 1)
    			System.out.println("NOT SURE");*/
    	}
    	    	
    }
    
    private int sumAround(int[] goodPass, int n, int numAngles) {
		int res = 0;
    	for (int i = n - numAngles; i <= n + numAngles; ++i){
			int k = i % goodPass.length;
			if (k < 0)
				k+= goodPass.length;
			res += goodPass[k];
		}
		return res;
	}
    
    private void updateEnemies(Point[] enemies){
    	if (this.enemies == null){
    		this.enemies = enemies;
    		return;
    	}
    	for (int i = 0; i < enemies.length; ++i){
    		if (Utils.Distance(this.enemies[i],enemies[i]) > 10){
    			this.enemies = enemies;
    			return; // A goal just happened
    		}
    	}
    		
    	
    	for (int i = 0; i < enemiesSpeed.length; ++i){
    		int dist = (int) Utils.Distance(this.enemies[i], enemies[i]);
    		enemiesSpeed[i] = Math.max(enemiesSpeed[i], dist);
    		if (rand.nextFloat() < 0.01f) // Decrease from time to time player speed
    			enemiesSpeed[i]--;
    	}
    		
    	this.enemies = enemies;    	
		for (int i = 0; i < enemiesSpeed.length; ++i)
			everybodySpeed[i + playersSpeed.length] = enemiesSpeed[i];		
    }

	public Vector<Comando> getComandos(SituacionJugadores sj){
    	b = sj.getBola();
    	nearest = sj.getMasCercanoDeBola();
    	Vector<Comando> actions = new Vector<Comando>();
    	players = sj.getMisJugadores();
    	updateEnemies(sj.getContrario());
    	
    	bh.setNewPosition(sj.getBola());
    	fs.setPlayersPosition(players);  	
    	
    	int maxStrength = 0;
    	for (int i = 0; i < players.length; i ++){
    		int str = 10 - playersSpeed[i];
    		if (Utils.Distance(players[i], b) < 9d && str > maxStrength){
    			maxStrength = str;
    			nearest = i;
    		}
    	}
    	
    	
    	int j = 0;
    	for (int i = 0; i < players.length; i ++)
    		everybody[j++] = players[i];
    	for (int i = 0; i < enemies.length; i ++)
    		everybody[j++] = enemies[i];    	
    	
    	//System.out.println("Calculated : " + bh.getSpeed() + " (" + b.getX() + "," + b.getY() + ")\n");	 	
    	
    	// Stick to the initial position and move a bit with the ball
    	for (int i = 0; i < 11; i++)
    	{
    		if (i > 0 && Utils.Distance(new Point (spositions[i][0],spositions[i][1]), players[i]) < 50 || Utils.Distance(new Point (spositions[i][0],spositions[i][1]), players[i]) < 10 /*&& Utils.isNearestPlayerInAdvantage(i, b, players, enemies)*/)
    			actions.add(new ComandoIrA(i,b.getX(),b.getY()));
    		else
    			actions.add(new ComandoIrA(i,Math.min(spositions[i][0], 140), spositions[i][1]));
    		
    		
    		if (!sj.estoyMasCercaDeBola()){
	    		ArrayList<Integer> playersAvailable = new ArrayList<Integer>();
	    		for (int z = 1; z < 6; ++z)
	    			playersAvailable.add(new Integer(z));
	    		for (int z = 0; z < enemies.length; ++z){
	    			if (enemies[z].x <= 0){
	    				double distMin = 1000;
	    				int playerMin = 0;
	    				for (int k = 0; k < playersAvailable.size(); ++k){
	    					double dist = Utils.Distance(enemies[z], players[playersAvailable.get(k)]);
	    					if (dist < distMin){
	    						distMin = dist;
	    						playerMin = playersAvailable.get(k);
	    					}
	    				}
	    				actions.add(new ComandoIrA(playerMin, enemies[z].getX(), enemies[z].getY()));    
	    			}    							
	    		}	 
    		}
    		
    	}

    	 	
    	if (nearest != 0 || Utils.Distance(players[nearest], b) < 40)
    		actions.add(new ComandoIrA(nearest,b.getX(),b.getY()));
    	
    	FutureNearest fn = fs.getFutureNearestPlayer();
    	actions.add(new ComandoIrA(fn.getPlayer(), fn.getX(), fn.getY()));

    	
    	if (Utils.Distance(players[nearest], b) < 10 && bh.getSpeed() < 15)
    	{
    		color = true;
    		for (int p = 10; p >= 0; --p)
    		{
    			if (Utils.Distance(players[p], b) < 10){ // Select a player which is near the ball, and with the highest number
    				whatToDo(p, actions);
    				break;
    			}
    		}
    	}  
    	else{
    		color = false;
    	}
    		 
    	
    	return actions;
    }
    
}

